home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / loadavg / loadavg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-24  |  11.1 KB  |  472 lines

  1. /*
  2.  * loadavg.c --
  3.  *
  4.  *    Provide access to the load average information database.  
  5.  *
  6.  * Copyright 1990 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/cmds/loadavg/RCS/loadavg.c,v 1.13 90/09/24 14:37:42 douglis Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20.  
  21. #include <sprite.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <mig.h>
  25. #include <kernel/net.h>
  26. #include <option.h>
  27. #include <host.h>
  28. #include <syslog.h>
  29. #include <sys/time.h>
  30. #include <sysStats.h>
  31.  
  32. /*
  33.  * Define constants for defaults values of variables that may be assigned
  34.  * by command-line arguments.
  35.  */
  36.  
  37. int allHosts = 0;
  38. int getLoad = 0;
  39. int debug = 0;
  40. int zapHostInfo = 0;
  41. int forceEvict = 0;
  42. int stripDomain = 1;
  43.  
  44. Option optionArray[] = {
  45.     {OPT_TRUE, "l", (char *)&getLoad,
  46.          "Get the load average of this node (DEFAULT)."},
  47.     {OPT_TRUE, "a", (char *)&allHosts,
  48.          "Get the load average of all nodes."},
  49.     {OPT_FALSE, "S", (char *)&stripDomain,
  50.          "Don't strip the domain from host names."},
  51.     {OPT_TRUE, "E", (char *)&forceEvict, "Evict foreign processes immediately."},
  52.     {OPT_TRUE, "D", (char *)&debug, "Enable debugging information."},
  53.     {OPT_TRUE, "Z", (char *)&zapHostInfo,
  54.          "Zap (remove) the information for hosts specified as remaining arguments."},
  55. };
  56. static int numOptions = sizeof(optionArray) / sizeof(Option);
  57.  
  58. /*
  59.  * Global variables.
  60.  */
  61. struct timeval currentTime;
  62. int hostID;
  63. #define HOST_NAME_LENGTH 64
  64. char hostname[HOST_NAME_LENGTH];
  65. char *machType;
  66. char *myName = NULL;
  67. int migVersion;
  68. int kernelState;
  69.  
  70.  
  71. static void ListHosts();
  72. static void OutputStatus();
  73. static void ZapHostInfo();
  74. extern char *rindex();
  75.  
  76.  
  77. /*
  78.  *----------------------------------------------------------------------
  79.  *
  80.  * Main --
  81.  *
  82.  *    The driver for the loadavg program.  Parse options and invoke
  83.  *    subroutines as appropriate.
  84.  *
  85.  * Results:
  86.  *    None.
  87.  *
  88.  * Side effects:
  89.  *    Initializes global variables.
  90.  *
  91.  *----------------------------------------------------------------------
  92.  */
  93.  
  94. int
  95. main(argc, argv)
  96.     int argc;
  97.     char *argv[];
  98. {
  99.     int status;
  100.     int numScanned;
  101.     int i;
  102.     int host;
  103.     Mig_Info *infoPtr;
  104.     Host_Entry *hostPtr;
  105.     
  106.  
  107.     argc = Opt_Parse(argc, argv, optionArray, numOptions,
  108.                OPT_ALLOW_CLUSTERING);
  109.  
  110.     myName = rindex(argv[0], '/');
  111.     if (myName){
  112.     myName++;
  113.     } else {
  114.     myName = argv[0];
  115.     }
  116.  
  117.     /*
  118.      * Process interrelated defaults and perform sanity checking on
  119.      * arguments.
  120.      */
  121.  
  122.     /*
  123.      * Default operation is to get the local load.
  124.      */
  125.  
  126.     if (! (getLoad || allHosts || zapHostInfo || forceEvict)) {
  127.     if (!strcmp(myName, "rup")) {
  128.         allHosts = 1;
  129.     } else if (!strcmp(myName, "evict")) {
  130.         forceEvict = 1;
  131.     } else {
  132.         getLoad = 1;
  133.     }
  134.     }
  135.  
  136.     /*
  137.      * Initialize global variables.
  138.      */
  139.     if (gethostname(hostname, sizeof(hostname)) < 0) {
  140.     perror("gethostname");
  141.     exit(1);
  142.     }
  143.     hostPtr = Host_ByName(hostname);
  144.     if (hostPtr == (Host_Entry *) NULL) {
  145.     fprintf(stderr, "error getting host information for '%s'.\n",
  146.            myName);
  147.     exit(1);
  148.     }
  149.     hostID = hostPtr->id;
  150.     machType = malloc((unsigned) strlen(hostPtr->machType) + 1);
  151.     if (machType == (char *) NULL) {
  152.     panic("Out of memory");
  153.     }
  154.     (void) strcpy(machType, hostPtr->machType);
  155.     
  156.     /*
  157.      * Get our migration version.
  158.      */
  159.     status = Sys_Stats(SYS_PROC_MIGRATION, SYS_PROC_MIG_GET_VERSION,
  160.                (Address) &migVersion);
  161.     if (status != SUCCESS) {
  162.     fprintf(stderr, "Error in Sys_Stats getting migration version: %s\n",
  163.         Stat_GetMsg(status));
  164.     exit(Compat_MapCode(status));
  165.     }
  166.     /*
  167.      * Get the kernel's idea of what we're importing and exporting.
  168.      */
  169.     status = Sys_Stats(SYS_PROC_MIGRATION, SYS_PROC_MIG_GET_STATE,
  170.                (Address) &kernelState);
  171.     if (status != SUCCESS) {
  172.     (void) fprintf(stderr,
  173.                "%s: warning: error in Sys_Stats getting migration state.\n",
  174.                myName);
  175.     kernelState = PROC_MIG_ALLOW_DEFAULT;
  176.     }
  177.     if (debug) {
  178.         (void) fprintf(stderr,
  179.                "My hostID is %d.  machType is %s.  kernel state is 0x%x.\n",
  180.                hostID, machType, kernelState);
  181.     }
  182.     status = gettimeofday(¤tTime, (struct timezone *) NULL);
  183.     if (status == -1) {
  184.     perror("Error in gettimeofday");
  185.     exit(1);
  186.     }
  187.  
  188.     if (zapHostInfo) {
  189.     for (i = 1; i < argc; i++) {
  190.         ZapHostInfo(argv[i]);
  191.     }
  192.     }
  193.     if (allHosts) {
  194.     ListHosts();
  195.     } else if (getLoad) {
  196.     infoPtr = Mig_GetInfo((int) PROC_MY_HOSTID);
  197.     if (infoPtr == (Mig_Info *) NULL) {
  198.         perror("Error in Mig_GetInfo");
  199.         exit(1);
  200.     }
  201.     OutputStatus(infoPtr);
  202.     }
  203.  
  204.     if (forceEvict) {
  205.     int numEvicted = Mig_Evict();
  206.     if (numEvicted < 0) {
  207.         perror("Mig_Evict");
  208.     } else {
  209.         printf("Evicted %d foreign processes.\n", numEvicted);
  210.     }
  211.     }
  212.     exit(0);
  213. }
  214.  
  215.  
  216. /*
  217.  *----------------------------------------------------------------------
  218.  *
  219.  * ListHosts --
  220.  *
  221.  *    Output the load average and status of all nodes.
  222.  *
  223.  * Results:
  224.  *    None.
  225.  *
  226.  * Side effects:
  227.  *    The data are is written to stdout.
  228.  *
  229.  *----------------------------------------------------------------------
  230.  */
  231.  
  232. static void
  233. ListHosts()
  234. {
  235.     int numRecs;
  236.     register Mig_Info *infoPtr;
  237.     Mig_Info *infoArray;
  238.     int i;
  239.     int maxSize;
  240.     int hostID;
  241.     int status;
  242.  
  243.     if (debug) {
  244.     (void) fprintf(stderr, "ListHosts called.\n");
  245.      (void) fflush(stderr);
  246.     }
  247.  
  248.     i = gettimeofday(¤tTime, (struct timezone *) NULL);
  249.     if (i == -1) {
  250.     perror("Error in gettimeofday");
  251.     exit(1);
  252.     }
  253.  
  254.     maxSize = NET_NUM_SPRITE_HOSTS * sizeof(Mig_Info);
  255.     infoArray = (Mig_Info *) malloc((unsigned) maxSize);
  256.     numRecs = Mig_GetAllInfo(infoArray, NET_NUM_SPRITE_HOSTS);
  257.     if (numRecs < 0) {
  258.     perror("Error in Mig_GetAllInfo");
  259.     exit(1);
  260.     }
  261.     if (debug && numRecs == 0) {
  262.     (void) fprintf(stderr, "No host records found.\n");
  263.      (void) fflush(stderr);
  264.     return;
  265.     }
  266.     
  267.     printf("            HOST     TYPE      STATUS       MIG     LOAD AVERAGE   IDLE TIME\n");
  268.  
  269.     for (i = 0; i < numRecs; i++) {
  270.     OutputStatus(&infoArray[i]);
  271.     }
  272.     free((char *) infoArray);
  273. }
  274.  
  275.  
  276. /*
  277.  *----------------------------------------------------------------------
  278.  *
  279.  * OutputStatus --
  280.  *
  281.  *    Determine the status of the given host and write a "ruptime"-like
  282.  *    record to stdout.
  283.  *
  284.  * Results:
  285.  *    None.
  286.  *
  287.  * Side effects:
  288.  *    None.
  289.  *
  290.  *----------------------------------------------------------------------
  291.  */
  292.  
  293. /*
  294.  * Size of the buffer for the current host's name.
  295.  */
  296. #define HOST_NAME_SIZE 64
  297.  
  298. /*
  299.  * Size of the buffer for reporting up- or down-time.
  300.  */
  301. #define TIME_STR_LEN 13
  302.  
  303. /*
  304.  * For Time_ToAscii, if relative time is specified, the time value is
  305.  * interpreted as the difference between two absolute time values and
  306.  * has the form:
  307.  *        0 days, 02:45:09
  308.  *                 ^^^
  309.  * SECOND_OFFSET is used to hide the seconds field by overwriting the colon
  310.  * with a null character.
  311.  */
  312. #define SECOND_OFFSET 9
  313.  
  314. static void
  315. OutputStatus(infoPtr)
  316.     register Mig_Info *infoPtr;
  317. {
  318.     int state;
  319.     char idleTime[TIME_STR_LEN];
  320.     char *idlePtr;
  321.     char timeStr[TIME_STR_LEN];
  322.     char upStr[5];
  323.     char stateStr[8];
  324.     char migOK;
  325.     char hostName[HOST_NAME_SIZE];
  326.     register char *hp;
  327.     register char *sp;
  328.     register int i;
  329.     int diff;
  330.     Host_Entry *hostPtr;
  331.  
  332.     hostPtr = Host_ByID(infoPtr->hostID);
  333.     if (hostPtr == (Host_Entry *) NULL) {
  334.     syslog(LOG_WARNING, 
  335.            "error in Host_ByID(%d).\n", infoPtr->hostID);
  336.     return;
  337.     }
  338.     /*
  339.      * Copy the name of the host, up to HOST_NAME_SIZE or the first
  340.      * '.' so we don't output the domain.
  341.      */
  342.     for (sp = hostName, hp = hostPtr->name, i = 0;
  343.      i < HOST_NAME_SIZE && *hp != '\0' && (!stripDomain || *hp != '.');
  344.      sp++, hp++, i++) {
  345.     *sp = *hp;
  346.     }
  347.     *sp = '\0';
  348.     
  349.  
  350.     /*
  351.      * See if the entry is out of date.  (Assume that anything updated
  352.      * after the current time is fairly recent and is caused by clock
  353.      * skew, so negative diffs are okay.)
  354.      */
  355.     state = infoPtr->state;
  356.     if (state == MIG_HOST_DOWN) {
  357.     diff = currentTime.tv_sec - infoPtr->loadVec.timestamp;
  358.     } else {
  359.     /*
  360.      * We want to know how long the machine has been up.
  361.      */
  362.     diff = infoPtr->loadVec.timestamp - infoPtr->bootTime;
  363.     if (diff < 0) {
  364.         (void) fprintf(stderr,
  365.                "Change was made before boot time??  modTime %d, bootTime %d, host %s.\n",
  366.                infoPtr->loadVec.timestamp, infoPtr->bootTime,
  367.                hostPtr->name);
  368.         diff = 0;
  369.     }
  370.     }
  371.         
  372.  
  373.     Time_ToAscii(diff, 1, timeStr);
  374.     timeStr[SECOND_OFFSET] = '\0';
  375.  
  376.     /*
  377.      * We allow migration if it's the right version,
  378.      * the file says to allow it, the entry in the
  379.      * file is current, we're exporting, and it is the same machine type.
  380.      * We're only concerned with normal priority processes, so we check
  381.      * against the max count if the host is partially in use.
  382.      */
  383.     migOK = ' ';
  384.     if (state != MIG_HOST_DOWN) {
  385.     if (infoPtr->loadVec.allowMigration) {
  386.         if ((state == MIG_HOST_PART_USED) || (state == MIG_HOST_FULL)) {
  387.         strcpy(stateStr, "hasmig");
  388.         } else {
  389.         strcpy(stateStr, "avail");
  390.         }
  391.         if (!strcmp(hostPtr->machType, machType)) {
  392.         if (infoPtr->migVersion != migVersion) {
  393.             strcpy(stateStr, "refuses");
  394.         } else if (hostPtr->id != hostID &&
  395.                state != MIG_HOST_FULL &&
  396.                infoPtr->foreign[MIG_NORMAL_PRIORITY] <
  397.                infoPtr->maxProcs) {
  398.             migOK = '*';
  399.         }
  400.         }
  401.     } else if (infoPtr->state == MIG_HOST_REFUSES) {
  402.         strcpy(stateStr, "refuses");
  403.     } else {
  404.         strcpy(stateStr, "inuse");
  405.     }
  406.     strcpy(upStr, "up");
  407.     } else {
  408.     strcpy(upStr, "down");
  409.     stateStr[0] = '\0';
  410.     }
  411.     (void) fprintf(stdout,
  412.            "%16s%c  %6s %4s %s %7s",
  413.            hostName, migOK,
  414.            hostPtr->machType,
  415.            upStr,
  416.            timeStr,
  417.            stateStr);
  418.     if (state != MIG_HOST_DOWN) {
  419.     (void) fprintf(stdout,
  420.                " %5.2lf %5.2lf %5.2lf",
  421.                infoPtr->loadVec.lengths[0], infoPtr->loadVec.lengths[1],
  422.                infoPtr->loadVec.lengths[2]);
  423.     if ((state != MIG_HOST_ACTIVE) || (infoPtr->loadVec.noInput > 60)) {
  424.         Time_ToAscii(infoPtr->loadVec.noInput, 1, idleTime);
  425.         idleTime[SECOND_OFFSET] = '\0';
  426.         for (idlePtr = idleTime; *idlePtr == ' '; idlePtr++) {
  427.         }
  428.         fprintf(stdout, " (%s)", idlePtr);
  429.     }
  430.     }
  431.     (void) fprintf(stdout, "\n");
  432. }
  433.  
  434.  
  435.  
  436. /*
  437.  *----------------------------------------------------------------------
  438.  *
  439.  * ZapHostInfo --
  440.  *
  441.  *    Zero out the information for a host.
  442.  *
  443.  * Results:
  444.  *    None.
  445.  *
  446.  * Side effects:
  447.  *    The global database is modified.
  448.  *
  449.  *----------------------------------------------------------------------
  450.  */
  451.  
  452. static void
  453. ZapHostInfo(hostname)
  454.     char *hostname;
  455. {
  456.     ReturnStatus status;
  457.     Mig_Info info;
  458.     Host_Entry *hostPtr;
  459.     
  460.  
  461.     hostPtr = Host_ByName(hostname);
  462.     if (hostPtr == (Host_Entry *) NULL) {
  463.     (void) fprintf(stderr, "ZapHostInfo: couldn't get info for %s.\n",
  464.                hostname);
  465.     return;
  466.     }
  467.     status = Mig_DeleteHost(hostPtr->id);
  468.     if (status != 0) {
  469.     perror("Error in Mig_DeleteHost");
  470.     }
  471. }
  472.